
#include "../coredef.h"
#include "cppdef.h"


/*------------------------------------------------------------------*/
/* CppCtl用グローバル変数												*/
/*------------------------------------------------------------------*/
/* 前処理指令処理関数表 */
typedef	struct	_CPPDEF {
	PSZ	    pszCppDef;				/* ﾌﾟﾘﾌﾛｾｯｻ文字列		*/
	U2	usCondKind;				/* 命令種別			*/
	S4	    ( *pFunc )();			/* 要求処理関数		*/
	U4	ulDefStr;				/* ﾌﾟﾘﾌﾟﾛｺﾏﾝﾄﾞ文字列長	*/
} CPPDEF , *PCPPDEF;

static CPPDEF	stCPPDef[] = {
	{"define"  ,	CPPDEF_DEF		, CppDefMain	,	0	},
	{"endif"   ,	CPPDEF_ENDIF	, CppEndifMain	,	0	},
	{"else"    ,	CPPDEF_ELSE		, CppElseMain	,	0	},
	{"ifdef"   ,	CPPDEF_IFDEF	, CppIfdefMain	,	0	},
	{"ifndef"  ,	CPPDEF_IFNDEF	, CppIfndefMain	,	0	},
	{"if"      ,	CPPDEF_IF		, CppIfMain		,	0	},
	{"elif"    ,	CPPDEF_ELIF		, CppElifMain	,	0	},
	{"undef"   ,	CPPDEF_UNDEF	, CppUndefMain	,	0	},
	{"include_next", CPPDEF_INCNEXT , CppIncNextMain    ,   0   },
	{"include" ,	CPPDEF_INC		, CppIncMain	,	0	},
	{"line"    ,	CPPDEF_LINE		, CppLineMain	,	0	},
	{"error"   ,	CPPDEF_ERROR	, CppErrorMain	,	0	},
	{"pragma"  ,	CPPDEF_PRAGMA	, CppPragmaMain	,	0	},
	{""        ,	CPPDEF_BASE		, NULL	        ,	0	}
} ;





/************************************************************************/
/* 関 数 名 : cppCtlBlankLine												*/
/* 機    能 :	空行判断														*/
/* 引 き 数 : 	pszLine	指定のファイルの１行										*/
/* 戻 り 値 :	TRUE	空行													*/
/*			FALSE	空行ではない											*/
/************************************************************************/
static BOOL cppCtlBlankLine( PSZ pszLine )
{
	register PSZ p_pszLine ;

	/* pszLineはNULLの場合 */
	if(pszLine == NULL)
	{
		return TRUE;
	}

	/* pszLineの文字列長は0である場合 */
	if(strlen(pszLine) == 0)
	{
		return TRUE;
	}

	p_pszLine = pszLine;

	while(TRUE)
	{
		if(*p_pszLine == '\0')
		{
			break;
		}
		else if( isspace(*p_pszLine) != 0 )
		{
			p_pszLine++;
			continue;
		}
		else
		{
		    break ;
		}
	}

	if(*p_pszLine == '\0')
	{
		return  TRUE;
	}

	return  FALSE;
}


/******************************************************************
* 関 数 名 : cppCtlFileRead
* 機    能  : 指定されたファイルから、一行を読み出す
* 引    数  : ファイルハンドル
* 戻 り 値 : EXIT_SUCCESS 成功
* 		  EXIT_FILEEND　ファイルエンド
*         EXIT_FATAL   致命エラー
* 詳細内容 :
*******************************************************************/
static S4 cppCtlFileRead ( HFILE hFile )
{
    BOOL 	bret;
    S4  	iret;              /* 戻り値_file      */
    BOOL 	bIscon;            /* 行連結フラグ             */
    AST    len;
    PSZ	    pszReadStart;	   /* 一行読込み開始位置  */
	U4	    ulReadLeng;	       /* 一行読込み文字列長  */
	U4      lineNum = 0;

    /* バッファーKIND_BUFREADをクリアする */
	bret = stCppReadBufferAccess.empty();
	if( bret == FALSE )
	{
		return COEXIT_FATAL;
	}
    /* １行を読み込む */
    iret = FileReadWholeLine( hFile, &pszReadStart, &ulReadLeng);
    if (iret == COEXIT_FATAL )
    {
        /* ### lastErrorをチェックし、該当するメッセージを出す */
        /* EXIT_FATALを返す                                                  */
        return (COEXIT_FATAL);
    }
    /* 「行連結フラグ」をFALSEと設定 */
    bIscon = FALSE;

    /* while 戻り値は正常終了 */
    while ( iret == COEXIT_SUCCESS )
    {
        if( bIscon == FALSE)
        {
        	/* 読み込んだ行は空行である場合 */
        	bret = cppCtlBlankLine(pszReadStart);
        	if ( bret == TRUE )
        	{
        		/* １行を読み込む */
        		iret = FileReadWholeLine( hFile, &pszReadStart, &ulReadLeng);
                if (iret == COEXIT_FATAL )
                {
                	/* 予約                                                                        */
                    /* ### lastErrorをチェックし、該当するメッセージを出す */
                    return (COEXIT_FATAL);
                }
                lineNum++;
                FATAL_ON_FATAL(CppLineFeed());
                continue;
        	}
        }

        /* 読み込んだ行は改行文字で終らない場合 */
        if(pszReadStart[ulReadLeng - 1] != '\n')
        {
        	CODESCOPE_CMP temp;
        	temp.fileindex = stCppNestFileInfoAccess.fileIndex.get(stCppNestFileInfoAccess.getMax());
        	temp.beginLine = stCppNestFileInfoAccess.physicalLine.get( stCppNestFileInfoAccess.getMax() );
        	temp.endLine = temp.beginLine+lineNum;
        	temp.offset_begin = 0;
        	temp.offset_end = ulReadLeng - 1;
    		CppThrowWarning( CPP_SRC_NEXTLINE_NOTFOUND,
    				stCoreCodeScpAccess.getCodeScp(&temp),
    				NULL, NULL );
        	/* 読み込んだ行を　バッファーKIND_BUFREAD　に追加する */
        	stCppReadBufferAccess.appendStr( MIN_ARRAY, pszReadStart );

            /* 「行連結フラグ」をFALSEと設定 */
            bIscon = FALSE;

            if (pszReadStart[ulReadLeng-1] == '\\')
            {
                FATAL_ON_FALSE(stCppReadBufferAccess.deleteChar(2));
            }
            else
            {
                FATAL_ON_FALSE(stCppReadBufferAccess.deleteChar(1));
            }
            stCppReadBufferAccess.appendStr( MIN_ARRAY, "\n" );
            break;
        }

        /* if  読み込んだ行は改行文字で終る場合 */
        if ( pszReadStart[ulReadLeng-1] == '\n' )
        {
        	/*if  読み込んだ行は改行文字の前に"\"がある場合 */
        	if (ulReadLeng > 1 && pszReadStart[ulReadLeng-2] == '\\')
        	{
        		bIscon = TRUE;
        		stCppReadBufferAccess.appendStr( MIN_ARRAY, pszReadStart );

        		iret = FileReadWholeLine(hFile, &pszReadStart, &ulReadLeng);
                if (iret == COEXIT_FATAL )
                {
                    /* EXIT_FATALを返す */
                    return (COEXIT_FATAL);
                }
                lineNum++;
                continue;
        	}
        }
        stCppReadBufferAccess.appendStr( MIN_ARRAY, pszReadStart );
        bIscon = FALSE;
        break;
    }

    if( iret == COEXIT_FILEEND)
    {
    	    /* ソースを読み込まない場合 */
    	if (stCppReadBufferAccess.isBlank()){
    		return (COEXIT_FILEEND);
    	}
    	pszReadStart = stCppReadBufferAccess.getStr(MIN_ARRAY);
    	len = str_length(pszReadStart);
        if( len == 0 )
		{
			return (COEXIT_FILEEND);
		}
		else
		{
			if( bIscon == TRUE)
			{
	        	CODESCOPE_CMP temp;
	        	temp.fileindex = stCppNestFileInfoAccess.fileIndex.get(stCppNestFileInfoAccess.getMax());
	        	temp.beginLine = stCppNestFileInfoAccess.physicalLine.get( stCppNestFileInfoAccess.getMax() );
	        	temp.endLine = temp.beginLine+lineNum;
	        	temp.offset_begin = 0;
	        	temp.offset_end = ulReadLeng - 1;
	    		CppThrowWarning( CPP_SRC_NEXTLINE_NOTFOUND,
	    				stCoreCodeScpAccess.getCodeScp(&temp),
	    				NULL, NULL );
				/* バッファーKIND_BUFREADに　"\n"を追加 */
				 stCppReadBufferAccess.appendStr( MIN_ARRAY, "\n" );
			}
			else
			{
			}
		}

    }
    /* 戻り値は異常終了の場合 */
    else if ( iret == COEXIT_FATAL )
    {
    	/* EXIT_CPPFATALを返す */
        return (COEXIT_FATAL );
    }

    return (COEXIT_SUCCESS);
}



/************************************************************************/
/* 関 数 名 : cppCtlFileClose												*/
/* 機    能 :	ﾌｧｲﾙｸﾛｰｽﾞ処理													*/
/* 引 き 数 : 	VOID														*/
/* 戻 り 値 :	COEXIT_SUCCESS		正常終了									*/
/* 			COEXIT_FATAL		致命エラー									*/
/************************************************************************/
static  S4 cppCtlFileClose(VOID)
{
	S4 iRetTemp;	/* 関数の戻り値 */
	S4 iRet;
	AST iKindIndex ;	/* テーブル連番 */
	S4 i;	/* COUNT */

	iKindIndex = stCppNestFileInfoAccess.getMax();

	iRetTemp = COEXIT_SUCCESS;
	for(i = MIN_ARRAY; i <= iKindIndex; i++)
	{
		iRet = FileClose( stCppNestFileInfoAccess.fileHandle.get(i) );
		iRetTemp = iRetTemp > iRet ? iRetTemp : iRet;
	}

	return ( iRetTemp );
}


/************************************************************************/
/* 関 数 名 : cppCtlFileEnd												*/
/* 機    能 :	該当するファイルを閉じる											*/
/* 引 き 数 : 	hFile	読み終わったファイルのハンドル								*/
/* 戻 り 値 :	COEXIT_SUCCESS		正常終了									*/
/* 			COEXIT_FATAL		致命エラー									*/
/* 詳細内容 	: 1. ﾌｧｲﾙｸﾛｰｽﾞする。											*/
/*          : 2. ｶﾚﾝﾄ情報ﾃｰﾌﾞﾙを開放する。                      			   		 	  	*/
/*          : 3. ｶﾚﾝﾄ情報ﾃｰﾌﾞﾙがある場合、終了#line出力処理をする。				*/
/************************************************************************/
static S4 cppCtlFileEnd(VOID)
{
	S4 RetTemp;	/* 各関連関数のリターンコード */
	HFILE hFile;
	AST nKindMax;
	nKindMax = stCppNestFileInfoAccess.getMax();
	hFile = stCppNestFileInfoAccess.fileHandle.get(nKindMax);
	/* hFileに該当するファイルを閉じる */
	RetTemp = FileClose(hFile);
	if(RetTemp != COEXIT_SUCCESS)
	{
		return(COEXIT_FATAL);
	}
	return COEXIT_SUCCESS;
}

S4 CppCtlGetFileBuffer( CHAR ** pBuffer )
{
	HFILE hFile;
	AST  nKindMax;
	S4  Ret;
	if( pBuffer != NULL )
	{
		*pBuffer = NULL;
		nKindMax = stCppNestFileInfoAccess.getMax();
		hFile = stCppNestFileInfoAccess.fileHandle.get(nKindMax);
		Ret = cppCtlFileRead(hFile);
		if (Ret == COEXIT_FILEEND)
		{
			return Ret;
		}
		*pBuffer = stCppReadBufferAccess.getStr(MIN_ARRAY);
	}
	return COEXIT_SUCCESS;
}
/************************************************************************/
/* 関 数 名 : CppCtlReqMain												*/
/* 機    能 :	前期処理字句より処理を行う											*/
/* 引 き 数 : 	pszLine				読み込んだ1行の文字列						*/
/* 戻 り 値 :	COEXIT_SUCCESS		正常終了									*/
/* 			COEXIT_ERROR		コンパイルエラー								*/
/*			COEXIT_FATAL		致命エラー									*/
/************************************************************************/
S4 CppCtlReqMain(PSZ pszLine)
{
	S4 nOppCtlReqMainRet = COEXIT_SUCCESS;
	S4 nRet, i;
	AST nKindMax;
	U2 nTokenKind, nTrueFalse;
	PSZ pTokenName = NULL;
	/* 前処理字句列を取得する */
	nRet = CppTokenGetTokens(pszLine, FALSE);
	if (nRet == COEXIT_FATAL) {
		FATAL_ON_FATAL(CppTokensDelAll());
		return ( COEXIT_FATAL );
	}

	/* TokenKindを判断する */
	nTokenKind = stCppTokenAccess.tokenKind.get(CUR_TOKEN_INDEX);
	/* HSPACEとVSPACEを読み捨てる */
	if (nTokenKind == xPPTOKEN_VSPACE || nTokenKind == xPPTOKEN_HSPACE ) {
		nRet = CppTokenGetNextToken( TRUE, FALSE);
		if( nRet == COEXIT_FINISHED ){
			/*debug,12/10/11,S*/
			FATAL_ON_FATAL(CppTokensDelAll());
			/*debug,12/10/11,E*/
			return nOppCtlReqMainRet;
		}
		nTokenKind = stCppTokenAccess.tokenKind.get(CUR_TOKEN_INDEX);
	}

	if (nTokenKind == xPPTOKEN_SHARP) {
		/* 今の前処理字句は＃である */
		/* HSPACEとVSPACEを読み捨てる */
		nRet = CppTokenGetNextToken( TRUE, FALSE);
		if (nRet == COEXIT_FINISHED) {
			nOppCtlReqMainRet = COEXIT_SUCCESS;
		}else{
			nTokenKind = stCppTokenAccess.tokenKind.get(CUR_TOKEN_INDEX);
			if (nTokenKind != xPPTOKEN_SYM) {
				CppThrowWarning( CPP_COMMAND_KEYWORD_ILLEGAL,
						stCppTokenAccess.codeScp.get(CUR_TOKEN_INDEX),
						stCppTokenAccess.name.get(CUR_TOKEN_INDEX), NULL );
				nOppCtlReqMainRet = COEXIT_SUCCESS;
			}else {
				/* 今の前処理字句は識別子 */
				pTokenName = stCppTokenAccess.name.get(CUR_TOKEN_INDEX);
				/* 登録した識別子と一致すれば該当関数をコール */
				for (i = 0; stCPPDef[i].usCondKind != CPPDEF_BASE; i ++) {
					if (!strcmp(stCPPDef[i].pszCppDef, pTokenName)) {
						nOppCtlReqMainRet = stCPPDef[i].pFunc();
						break;
					}
				}
				/* 登録した識別子と一致しない場合は警告230Dを出す */
				if (stCPPDef[i].usCondKind == CPPDEF_BASE) {
					CppThrowWarning( CPP_COMMAND_KEYWORD_ILLEGAL,
							stCppTokenAccess.codeScp.get(CUR_TOKEN_INDEX),
							pTokenName, NULL );
					FATAL_ON_FATAL(CppTokensDelAll());
					nOppCtlReqMainRet = COEXIT_SUCCESS;
				}
			}
		}
	}else {
		/* マクロ置換、または無視 */
		nKindMax = stCppDirectiveIFGroupAccess.getMax();
		nTrueFalse = stCppDirectiveIFGroupAccess.state.get(nKindMax);
		if (nTrueFalse == TRUE) {
			nOppCtlReqMainRet = CppRepMain();
			FATAL_ON_FATAL(CppTokensDelAll());
		}else {
			/* 関　トークン削除 */
			FATAL_ON_FATAL(CppTokensDelAll());
			/* 関　トークン削除 */
			nOppCtlReqMainRet = COEXIT_SUCCESS;
		}
	}
	if( nOppCtlReqMainRet != COEXIT_FATAL )
	{
		nOppCtlReqMainRet = COEXIT_SUCCESS;
	}
	return ( nOppCtlReqMainRet );
}


/************************************************************************/
/* 関 数 名 : CppCtrlMain													*/
/* 機    能 :	前期処理関数													*/
/* 引 き 数 : 	pszSrc	ソースファイルのパス名										*/
/* 戻 り 値 :	COEXIT_SUCCESS		正常終了									*/
/* 			COEXIT_ERROR		コンパイルエラー								*/
/*			COEXIT_FATAL		致命エラー									*/
/************************************************************************/
S4 CppCtrlMain ( PSZ pszSrc )
{
	S4 RetTemp;					/* 関数の戻り値 */
	S4 Ret = COEXIT_SUCCESS ;		/* リターンコード */
	S4 i;							/* COUNT     */
	AST nKindMax;
	CHAR * p_GetProperty_String;

	gblErrorFlag = COEXIT_SUCCESS;
	/* stCPPDefの各メンバーの命令名長を反映する */
	for(i = 0; stCPPDef[i].usCondKind != CPPDEF_BASE ; i++)
	{
		stCPPDef[i].ulDefStr = strlen(stCPPDef[i].pszCppDef) ;
	}

	/* ソースオープン */
	RetTemp = CppIncAddCurrent(pszSrc, 0) ;
	if(RetTemp != COEXIT_SUCCESS) {
		return(RetTemp);
	}

	if( stCoreEnvInfo.ucCppResult ){
		/* 前処理結果ファイルをオープンする */
		FATAL_ON_FATAL( CppResultInit( pszSrc, NULL ) );
	}
	/* ソース処理 */
	RetTemp = COEXIT_SUCCESS;
	while(Ret == COEXIT_SUCCESS)
	{
		/* ソースまたはヘッダから一行を読み込む */
		Ret = CppCtlGetFileBuffer(&p_GetProperty_String);

		if (Ret == COEXIT_FILEEND)
		{
			/* オープンされたファイルがありません場合 */
			nKindMax = stCppNestFileInfoAccess.getMax();
			if (nKindMax == MIN_ARRAY)
			{
				Ret = CppIfFileFinished();
				if (Ret != COEXIT_SUCCESS)
				{
					RetTemp = Ret;
					break;
				}
			}
			/* ファイル終了処理 */
			Ret = cppCtlFileEnd();
			if (Ret != COEXIT_SUCCESS)
			{
				RetTemp = Ret;
				break;
			}
			Ret = CppIncPopCurrent();
			if (Ret != COEXIT_SUCCESS)
			{
				RetTemp = Ret;
				break;
			}
			nKindMax = stCppNestFileInfoAccess.getMax();
			if (nKindMax < MIN_ARRAY)
			{
				break;
			}
		}
		else if (Ret == COEXIT_SUCCESS)
		{
			/* 正常の場合 */
			Ret = CppCtlReqMain(p_GetProperty_String);
			if (Ret == COEXIT_FATAL) {
				RetTemp = Ret;
				break;
			}else {
				RetTemp = RetTemp > Ret ? RetTemp : Ret;
				Ret = COEXIT_SUCCESS;
			}
		}
		else
		{
			RetTemp = Ret;
			break;
		}
	}

	/* ファイルクローズ */
	if(Ret != COEXIT_SUCCESS)
	{
		cppCtlFileClose();
	}
	if( stCoreEnvInfo.ucCppResult )
	{
		/* 前処理結果ファイルをクローズする */
		Ret = CppResultTerminal(  );
		RetTemp = RetTemp > Ret ? RetTemp : Ret;
	}

	/* テンポラリ変数とgblErrorFlagの大きい方を返す */
	RetTemp = RetTemp > gblErrorFlag ? RetTemp : gblErrorFlag;
	return ( RetTemp );
}



